package Common

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	global "gPublic/Global"
	"io"
	"math"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	// "github.com/qiniu/api.v7/v7/auth/qbox"	// 弃用
	// "github.com/qiniu/api.v7/v7/storage"
	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/storage"
)

var (
	SUCCESS    = 2000
	ERROR      = 3000
	NOT_DELETE = 0
	MYSECRET   = []byte("KsLYcwVNh0W1mmxgy43TjsQtXVIi")
	TotalPages int
	TotalRows  int64
	Err        error
)

type Logger struct {
	Status int
	Msg    string
	Data   interface{}
}

type ResData struct {
	Code int         `json:"code"` // 状态码
	Msg  interface{} `json:"msg"`  // 具体描述信息
	Data interface{} `json:"data"` // 数据
}

type ResDataToken struct {
	Token string
}

type Page struct {
	Page  int `json:"page" form:"page"`
	Size  int `json:"size" form:"size"`
	Total int `json:"total" form:"total"`
}

// 时间戳 转 时间
func UnixToTime(timestamp int) string {
	t := time.Unix(int64(timestamp), 0)
	return t.Format("2006-01-02 15:04:05")
}

// 时间 转 时间戳
func TimeToUnix(str string) int64 {
	template := "2006-01-02 15:04:05"
	t, err := time.ParseInLocation(template, str, time.Local)
	if err != nil {
		return 0
	}
	return t.Unix()
}

// 日期 转 时间戳
func DateToUnix(str string) int64 {
	template := "2006-01-02"
	t, err := time.ParseInLocation(template, str, time.Local)
	if err != nil {
		return 0
	}
	return t.Unix()
}

// 获取时间戳
func GetUnix() int64 {
	return time.Now().Unix()
}

// 获取时间日期
func GetDateTime() string {
	tmp := "2006-01-02 15:04:05"
	return time.Now().Format(tmp)
}

// 获取年月日
func GetDate() string {
	tmp := "20060102"
	return time.Now().Format(tmp)
}

// 判断字符串是否在数组内
func IsInArray(target string, arr []string) bool {
	for _, item := range arr {
		if item == target {
			return true
		}
	}
	return false
}

func Md5(input string) string {

	// 创建 MD5 加密器
	hash := md5.New()

	// 写入要加密的字节到加密器
	hash.Write([]byte(input))

	// 计算 MD5 校验和
	hashInBytes := hash.Sum(nil)

	// 将校验和格式化为 16 进制字符串
	md5String := hex.EncodeToString(hashInBytes)

	return md5String
}

// 拼七牛图片大小
func QiNiuImageAutoThumb(key string, width int64, expires int) string {
	widthTostring := strconv.FormatInt(width, 10)
	st := fmt.Sprintf("%s?imageMogr2/auto-orient/thumbnail/!%s/gravity/Center/crop/%sx/interlace/1/blur/1x0/quality/100", key, widthTostring, widthTostring)
	url, _ := DownloadUrl(st, expires)
	return url
}

// 七牛 私
func DownloadUrl(key string, expires int) (string, error) {
	mac := qbox.NewMac(global.Config.QiNiuYzInfo.Access_key, global.Config.QiNiuYzInfo.Secret_Key)
	baseURL := fmt.Sprintf("%s", global.Config.QiNiuYzInfo.Domain)
	expiresInSeconds := time.Now().Add(time.Duration(expires) * time.Second).Unix()
	privateURL := storage.MakePrivateURL(mac, baseURL, key, expiresInSeconds)
	return privateURL, nil
}

// video	m3u8视频地址授权播放
func GetVideoAuth(key string, expires int) string {
	mac := qbox.NewMac(global.Config.QiNiuYzInfo.Access_key, global.Config.QiNiuYzInfo.Secret_Key)

	deadline := time.Now().Unix() + 86400

	baseUrl := global.Config.QiNiuYzInfo.Domain + "/" + key

	pos := strings.Index(baseUrl, "?")

	if pos != -1 {
		baseUrl += "&pm3u8&e="
	} else {
		baseUrl += "?pm3u8&e="
	}
	baseUrl += fmt.Sprint(deadline)

	token := mac.Sign([]byte(baseUrl))

	return fmt.Sprintf("%s&token=%s", baseUrl, token)
}

// 对称加解密
func StrToXHex(c string) string {
	var scill []int
	lenC := len(c)
	a := 0

	for a < lenC {
		var ud int
		switch {
		case ord(c[a]) >= 0 && ord(c[a]) <= 127:
			ud = ord(c[a])
			a += 1
		case ord(c[a]) >= 192 && ord(c[a]) <= 223:
			ud = (ord(c[a])-192)*64 + (ord(c[a+1]) - 128)
			a += 2
		case ord(c[a]) >= 224 && ord(c[a]) <= 239:
			ud = (ord(c[a])-224)*4096 + (ord(c[a+1])-128)*64 + (ord(c[a+2]) - 128)
			a += 3
		case ord(c[a]) >= 240 && ord(c[a]) <= 247:
			ud = (ord(c[a])-240)*262144 + (ord(c[a+1])-128)*4096 + (ord(c[a+2])-128)*64 + (ord(c[a+3]) - 128)
			a += 4
		case ord(c[a]) >= 248 && ord(c[a]) <= 251:
			ud = (ord(c[a])-248)*16777216 + (ord(c[a+1])-128)*262144 + (ord(c[a+2])-128)*4096 + (ord(c[a+3])-128)*64 + (ord(c[a+4]) - 128)
			a += 5
		case ord(c[a]) >= 252 && ord(c[a]) <= 253:
			ud = (ord(c[a])-252)*1073741824 + (ord(c[a+1])-128)*16777216 + (ord(c[a+2])-128)*262144 + (ord(c[a+3])-128)*4096 + (ord(c[a+4])-128)*64 + (ord(c[a+5]) - 128)
			a += 6
		case ord(c[a]) >= 254 && ord(c[a]) <= 255:
			ud = -1 // Error handling placeholder
		}
		scill = append(scill, ud)
	}

	scillJSON, _ := json.Marshal(scill)
	// Assume str_secret is implemented in Go as well
	return StrSecret(string(scillJSON), "R1ZX1kLKkKQFAWWM", false) // Encryption key shared with frontend
}

func ord(b byte) int {
	return int(b)
}

// operation 为 true，则表示进行解密操作。 operation 为 false，则表示进行加密操作。
func StrSecret(input string, code string, operation bool) string {
	hash := md5.Sum([]byte(code))
	key := hash[:16]
	iv := hash[:aes.BlockSize]
	// iv := hash[16:]

	block, _ := aes.NewCipher(key)
	mode := cipher.NewCBCDecrypter(block, iv)

	if operation {
		decoded, _ := base64.StdEncoding.DecodeString(input)
		mode.CryptBlocks(decoded, decoded)
		return string(decoded)
	}

	padLen := aes.BlockSize - len(input)%aes.BlockSize
	padding := bytes.Repeat([]byte{byte(padLen)}, padLen)
	padded := append([]byte(input), padding...)
	encrypted := make([]byte, len(padded))
	mode = cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(encrypted, padded)

	return base64.StdEncoding.EncodeToString(encrypted)
}

// MergedMapInterface 城市树形结构
func MergedMapInterface(aMap []map[string]interface{}) []map[string]interface{} {
	fmt.Println("tree -----------------------------")
	a := int64(1)
	var data []map[string]interface{}
	for _, v := range aMap {
		if v["leveltype"] == a {
			data = append(data, getChildren(aMap, v))
		}
	}
	return data
}

// getChildren 城市树形结构 二级
func getChildren(cities []map[string]interface{}, city map[string]interface{}) map[string]interface{} {
	var children []map[string]interface{}
	for _, child := range cities {
		//fmt.Printf("id: %T, - parentid: %T\n", city["id"], child["parentid"])
		id := averConvert(city["id"])
		if int64(id.it32) == child["parentid"] {
			children = append(children, getChildren(cities, child))
		}
	}
	city["children"] = children
	return city
}

type aver struct {
	str  string
	it32 int32
	it64 int64
}

// averConvert 将interface{} 转为原类型 列入 原interface 类型是int32 则转为int32，和interface再也没有关系了
func averConvert(value interface{}) aver {
	var ra aver
	switch value.(type) {
	case string:
		// 将interface转为string字符串类型
		op, ok := value.(string)
		if ok {
			ra.str = op
		}
	case int32:
		// 将interface转为int32类型
		op, ok := value.(int32)
		if ok {
			ra.it32 = op
		}
	case int64:
		// 将interface转为int64类型
		op, ok := value.(int64)
		if ok {
			ra.it64 = op
		}
	}
	return ra
}

// 当前时间 和 制定时间相隔 年月日
func TimeDiff(beginTime, endTime int64) map[string]int64 {
	startTime, endTime := int64(0), int64(0)
	if beginTime < endTime {
		startTime = beginTime
		endTime = endTime
	} else {
		startTime = endTime
		endTime = beginTime
	}

	// 计算时间差
	timediff := endTime - startTime
	days := int64(math.Floor(float64(timediff) / 86400))
	remain := timediff % 86400
	hours := int64(math.Floor(float64(remain) / 3600))
	remain = remain % 3600
	mins := int64(math.Floor(float64(remain) / 60))
	secs := remain % 60
	res := map[string]int64{
		"day":  days,
		"hour": hours,
		"min":  mins,
		"sec":  secs,
	}
	return res
}

// post 请求
// func SendPostRequest(url string, headers map[string]string, body interface{}) (*http.Response, error) {
func SendPostRequest(url string, headers map[string]string, body interface{}) string {

	jsonData, err := json.Marshal(body)

	if err != nil {
		panic(err)
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		panic(err)
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}
	//req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	//req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	//req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	contents := make([]byte, 0)
	if resp.StatusCode == http.StatusOK {
		contents, err = io.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
	}
	return string(contents)
}

// 发送get请求
func SendGetRequest(url string, headers map[string]string) (string, error) {

	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return "", err
	}

	for key, val := range headers {
		req.Header.Set(key, val)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	contents := make([]byte, 0)
	if resp.StatusCode == http.StatusOK {
		contents, err = io.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
	}
	return string(contents), err
}

// AnyToStr 任意类型数据转string
func AnyToStr(i interface{}) (string, error) {

	if i == nil {
		return "", nil
	}

	v := reflect.ValueOf(i)
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return "", nil
		}
		v = v.Elem()
	}

	fmt.Println("--kind---", v.Kind())
	switch v.Kind() {
	case reflect.String:
		return v.String(), nil
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(v.Int(), 10), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return strconv.FormatUint(v.Uint(), 10), nil
	case reflect.Float32:
		return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil
	case reflect.Float64:
		return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
	case reflect.Complex64:
		return fmt.Sprintf("(%g+%gi)", real(v.Complex()), imag(v.Complex())), nil
	case reflect.Complex128:
		return fmt.Sprintf("(%g+%gi)", real(v.Complex()), imag(v.Complex())), nil
	case reflect.Bool:
		return strconv.FormatBool(v.Bool()), nil
	case reflect.Slice, reflect.Map, reflect.Struct, reflect.Array:
		str, _ := json.Marshal(i)
		return string(str), nil
	default:
		return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i)
	}
}

// 字节转兆
func BytesToMegabytes(bytes int64) string {
	megabytes := float64(bytes) / (1024.0 * 1024.0)
	megabytesStr := strconv.FormatFloat(megabytes, 'f', 2, 64)
	return megabytesStr
}

// func HttpPostForm(urlPath string, dt url.Values) (*http.Response, error) {
// 	r, err := http.PostForm(urlPath, dt)
// 	if err != nil {
// 		return nil, err
// 	}
// 	defer r.Body.Close()
// 	if r.StatusCode == http.StatusOK {
// 		return r, err
// 	} else {
// 		return nil, err
// 	}
// }
